package com.zusmart.base.network.support;

import java.nio.channels.SocketChannel;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.zusmart.base.activity.support.AbstractActivity;
import com.zusmart.base.network.ChannelContext;
import com.zusmart.base.network.ChannelContextManager;
import com.zusmart.base.network.handler.ChannelContextHandlerContext;
import com.zusmart.base.network.handler.support.DefaultChannelContextHandler;

public abstract class AbstractChannelContextManager extends AbstractActivity<ChannelContextManager> implements ChannelContextManager {

	private static final String HANDLER_NAME = "__CHANNEL_CONTEXT_MONITOR__";
	
	private final boolean serverSide;
	private final ConcurrentMap<String, ChannelContext> contexts = new ConcurrentHashMap<String, ChannelContext>();
	
	protected AbstractChannelContextManager(boolean serverSide){
		this.serverSide = serverSide;
	}
	
	@Override
	public boolean isClientSide() {
		return this.serverSide == false;
	}
	
	@Override
	public boolean isServerSide() {
		return this.serverSide == true;
	}
	
	@Override
	public ChannelContext createChannelContext(SocketChannel socketChannel) {
		String contextCode = this.createChannelContextCode();
		ChannelContext channelContext = this.doCreateChannelContext(contextCode, socketChannel);
		channelContext.getChannelContextHandlerChain().addFirst(HANDLER_NAME, new DefaultChannelContextHandler() {
			@Override
			public void onRegister(ChannelContext channelContext, ChannelContextHandlerContext handlerContext) {
				contexts.putIfAbsent(channelContext.getContextCode(), channelContext);
				super.onRegister(channelContext, handlerContext);
			}

			@Override
			public void unRegister(ChannelContext channelContext, ChannelContextHandlerContext handlerContext) {
				super.unRegister(channelContext, handlerContext);
				contexts.remove(channelContext.getContextCode(), channelContext);
			}
		});
		return channelContext;
	}

	@Override
	public ChannelContext getChannelContext(String contextCode) {
		return this.contexts.get(contextCode);
	}

	@Override
	public Map<String, ChannelContext> getChannelContexts() {
		return Collections.unmodifiableMap(this.contexts);
	}
	
	@Override
	public int getChannelContextSize() {
		return this.contexts.size();
	}

	@Override
	protected ChannelContextManager getActivity() {
		return this;
	}

	protected String createChannelContextCode() {
		return UUID.randomUUID().toString().toUpperCase();
	}

	protected abstract ChannelContext doCreateChannelContext(String contextCode, SocketChannel socketChannel);

}